/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * bocciawii
 * Copyright (C) Grupo de trabajo ULE 2010 <ulewii@googlegroups.com>
 * 
 * teclado is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * teclado is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _MENU_LAYOUT_H_
#define _MENU_LAYOUT_H_
#include "screen-layout.h"
#include "boton.h"

/**
 * @brief Clase menú básica.
 *
 * El motor también ofrece una implementación de <code>ScreenLayout</code>
 * orientada a menús. Posee toda la funcionalidad que ofrecía ésta, más la capacidad
 * de responder a eventos, selección de widgets enteros por ID, y asigna a los
 * <code>Boton</code> sus vecinos.
 *
 * La clase, utilizando de base <code>ScreenLayout</code>, tiene el mismo funcionamiento
 * que ésta, salvando algunos procedimientos que se han de ejecutar una vez creado el 
 * menú. Estos procedimientos tratan de establecer los enlaces y dejar seleccionado
 * uno de los contenidos por defecto.
 *
 * Es evidente, pero conviene remarcar que cada menú habrá de tener al menos un
 * hijo que pueda ser seleccionable.
 *
 * Los hijos serán vecinos de otros si son visibles y son seleccionables
 *
 * Un menú ofrece la posibilidad de que existan varios submenús.
 * Esto es útil cuando se quiere agrupar un menú con diversos submenús.
 * Por ejemplo, si se desea que un botón active uno de los submenús, lo único
 * que habría que hacer sería, en el callback de ese botón (menu = menu->GetSubMenu("menu_deseado"))
 * y se evita tener que cambiar de estado, o cambiar el menú del estado actual.
 */
class MenuLayout:public ScreenLayout
{
public:
	/**
	 * @brief Constructor, obtiene id para el menú, y al igual que su super-clase
	 * un número de filas y de columnas
	 *
	 * @param id Identificador del menú (único entre todos los menús)
	 * @param filas número de filas (> 1)
	 * @param cols número de columnas (> 1)
	 */
	MenuLayout(std::string id, int filas, int cols);
	~MenuLayout();

	/**
	 * @brief Establecer vecinos entre los hijos
	 *
	 * Un vecino se establece entre los que están en su misma fila y su misma columna
	 * sin importar cuántos espacios hay en medio.
	 *
	 * No está implementado ningún movimiento especial, por lo que es necesario
	 * que los elementos estén conexos por su coordenada de fila o de columna
	 * para que pueda existir una navegación entre ellos
	 */
	void EstablecerEnlaces();

	/**
	 * @brief Recuperar un hijo del MenuLayout
	 *
	 * Obtener un <code>Boton</code> que tenga la ID que se busca
	 * @param id ID a buscar
	 * @return <code>Boton<code> buscado, o NULL si no se encuentra
	 */
	Boton* GetContByID(std::string id);

	
	/**
	 * @brief Recuperar el hijo resaltado del MenuLayout
	 *
	 * Obtener el <code>Boton</code> que tiene el foco del usuario
	 * @return <code>Boton<code> resaltado, o NULL si no se encuentra
	 */
	Boton* GetHighlighted();

	/**
	 * @brief Recuperar el hijo resaltado del MenuLayout
	 *
	 * Obtener el <code>Boton</code> que tiene el foco del usuario
	 * @return <code>Boton<code> resaltado, o NULL si no se encuentra
	 */
	MenuLayout* GetSubMenu(std::string id);
	/**
	 * @brief Recuperar un widget deseado
	 *
	 * Obtener el <code>Elemento</code> que coincide con la identificación dada
	 * El menú buscará entre todos sus hijos al que contenga el que se busca
	 * de ahí que se aconsejara que todos los elementos tuvieran una id independiente
	 * de los demás del super-contenedor.
	 
	 * @return <code>Elemento<code> buscado, o NULL si no se encuentra
	 */
	Elemento* GetElemByID(std::string id);

	/**
	 * @brief Dibujado del MenuLayout
	 *
	 * Dibujará un "overlay" (un cuadrado con una transparencia dada encima de lo que 
	 * estuviera debajo), dibujará los hijos, y éstos dibujarán sus hijos.
	 */
	void Dibujar();

	/**
	 * @brief Devolver el padre de un menú
	 *
	 * Si el menú actual es un submenú de otro, se puede recuperar al padre con
	 * esta llamada.
	 *
	 * @return <code>MenuLayout</code> padre del actual. NULL si no tiene
	 */
	inline MenuLayout* GetParent()
	{   return supermenu;   }

	/**
	 * @brief Asignar un submenu al menú actual
	 *
	 * Se pueden asignar hasta un máximo de cinco submenús a un menú.
	 * Este procedimiento asigna un menú al actual, y hace al actual padre del
	 * dado, y al dado submenú del actual.
	 *
	 * @param <code>MenuLayout</code> que se quiera asignar.
	 */	
	void AsignarSubMenu(MenuLayout* menu);
	
	/**
	 * @brief Asignar padre al menú actual
	 
	 * @param <code>MenuLayout</code> padre del menú actual.
	 */	
	void AsignarPadre(MenuLayout* menu);

	/**
	 * @brief Obtener la ID del menú
	 
	 * @return string con el id del menú
	 */	
	inline std::string GetID()
	{	return _id;   }

	/**
	 * @brief Setter para la transparencia del "overlay"
	 * 
	 * El "overlay" es tan sólo, en nuestra aplicación, un cuadrado negro
	 * tan ancho y alto como la pantalla, de color negro, con un nivel de transparencia.
	 * Esto crea la impresión de que tienes algo más detrás, y que puedes volver
	 * atrás, en vez de crear un cambio tan brusco entre menús, que da la impresión
	 * de que algo se ha borrado o se ha perdido.
	 * @param trans 1 para completamente negro, 0 para completamente transparente
	 */	
	inline void SetOverlayTransparency(float trans)
	{	_transparency = trans;   }

	/**
	 * @brief Seleccionar un hijo por defecto.
	 * 
	 *Como se expuso en la clase, todo menú, para un funcionamiento correcto
	 * debe tener al menos un contenido seleccionable.
	 *
	 * Si se quiere que el menú tenga algo seleccionado por defecto (probablemente sea así)
	 * sin que haya que pulsar ningún botón, y evitando problemas de referencias a NULL
	 * hay que llamar a este procedimiento, o seleccionar un botón a mano.
	 *
	 * Por defecto, el elemento seleccionado es, de los que estén más arriba, el que está
	 * más a la izquierda.
	 */
	void SeleccionarDefecto();
	

protected:

private:
	void EstablecerEnlaces(int x, int y);

	std::string _id;
	MenuLayout* supermenu;

	MenuLayout* submenus[5];

	int _numSubmenus;

	float _transparency;

};

#endif // _MENU_LAYOUT_H_
